﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Xml;
using XmlDSigEx;
using System.Security.Cryptography.Xml;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Reflection;
using System.Security.Cryptography;

namespace TestCustomSigning
{
    [TestClass]
    public class TestSigner
    {
        /*
         * These tests may use the default RSA-SHA256 signature algorithm.
         * By default, the .Net Framework SignedXml classes do not support this algorithm and
         * some tests may fail. You must install and register the RSA SHA256 signature
         * description class. For more info see: http://clrsecurity.codeplex.com/wikipage?title=Security.Cryptography.RSAPKCS1SHA256SignatureDescription&referringTitle=Security.Cryptography.dll
         */
          
        
        [TestMethod]
        public void TestBasicSign()
        {
            string input = GetEmbeddedContent("TestCustomSigning.SAML2Request.xml");
            XmlDocument doc = new XmlDocument() { PreserveWhitespace = true };
            XmlReader reader = XmlReader.Create(new StringReader(input));

            doc.Load(reader);

            XmlSigner signer = new XmlSigner(doc);
            signer.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;
            signer.CanonicalisationMethod = SignedXml.XmlDsigExcC14NTransformUrl;

            XmlDSigEx.Reference refr = signer.CreateReference();
            refr.Uri = "";
            refr.AddTransform(SignedXml.XmlDsigEnvelopedSignatureTransformUrl);
          
            var cert = new X509Certificate2(GetEmbeddedBytes("TestCustomSigning.testcert.pfx"), "password");
            RSAX509Algorithm algorithm = new RSAX509Algorithm(cert);
            algorithm.KeyInfo = X509Data.X509Certificate;

            var element = signer.GetXml(algorithm);
            string output = element.OuterXml;
            doc.DocumentElement.AppendChild(doc.ImportNode(element, true));

            SignedXml xml = new SignedXml(doc);
            xml.LoadXml(element);
            bool result = xml.CheckSignature();

            Assert.IsTrue(result);
    }

        [TestMethod]
        public void TestXPathFilter2Sign()
        {
            string input = GetEmbeddedContent("TestCustomSigning.SAML2Request.xml");
            XmlDocument doc = new XmlDocument() { PreserveWhitespace = true };
            XmlReader reader = XmlReader.Create(new StringReader(input));

            doc.Load(reader);

            XmlSigner signer = new XmlSigner(doc);
            signer.CanonicalisationMethod = SignedXml.XmlDsigExcC14NTransformUrl;

            XmlDSigEx.Reference refr = signer.CreateReference();
            refr.Uri = "";

            XPathFilter2Transform transform = (XPathFilter2Transform)refr.AddTransform(XPathFilter2Transform.URI_XPATH2TRANSFORM);
            XPathFilter2Expression expression = transform.AddExpression(FilterType.Subtract, "here()/ancestor::ds:Signature[1]");
            expression.AddNamespace("ds", XmlSigner.NS_XMLDSIG);

            var cert = new X509Certificate2(GetEmbeddedBytes("TestCustomSigning.testcert.pfx"), "password");
            RSAX509Algorithm algorithm = new RSAX509Algorithm(cert);
            algorithm.KeyInfo = X509Data.X509Certificate;

            var element = signer.GetXml(algorithm);
            string output = element.OuterXml;
            doc.DocumentElement.AppendChild(doc.ImportNode(element, true));


            Assert.IsTrue(true);
        }

        [TestMethod]
        public void TestXPathFilter2SignAndVerify()
        {
            string input = GetEmbeddedContent("TestCustomSigning.SAML2Request.xml");
            XmlDocument doc = new XmlDocument() { PreserveWhitespace = true };
            XmlReader reader = XmlReader.Create(new StringReader(input));
            doc.Load(reader);

            XmlSigner signer = new XmlSigner(doc);
            signer.CanonicalisationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
            signer.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512";

            XmlDSigEx.Reference refr = signer.CreateReference();
            refr.Uri = "";
            refr.DigestMethod = SignedXml.XmlDsigSHA1Url;

            XPathFilter2Transform transform = (XPathFilter2Transform)refr.AddTransform(XPathFilter2Transform.URI_XPATH2TRANSFORM);
            XPathFilter2Expression expression = transform.AddExpression(FilterType.Subtract, "here()/ancestor::ds:Signature[1]");
            expression.AddNamespace("ds", XmlSigner.NS_XMLDSIG);

            refr.AddTransform(SignedXml.XmlDsigExcC14NTransformUrl);

            var cert = new X509Certificate2(GetEmbeddedBytes("TestCustomSigning.testcert.pfx"), "password");

            RSAX509Algorithm algorithm = new RSAX509Algorithm(cert);
            algorithm.KeyInfo = X509Data.X509Certificate;

            var element = signer.GetXml(algorithm);
            string output = element.OuterXml;

            doc.DocumentElement.AppendChild(doc.ImportNode(element, true));

            string signed = doc.OuterXml;
            XmlDocument signedDoc = new XmlDocument() { PreserveWhitespace = true };
            signedDoc.Load(XmlReader.Create(new StringReader(signed)));

            XmlSigner verifier = new XmlSigner(signedDoc);
            ISignatureAlgorithm algorithm2 = new RSAX509Algorithm(cert);
            bool result = verifier.ValidateSignature(signedDoc.DocumentElement.LastChild as XmlElement, algorithm);
            Assert.IsTrue(result);
        }

        [TestMethod]
        public void TestUnknownTransformOnPrecomputedDigestForSign()
        {
            string input = GetEmbeddedContent("TestCustomSigning.SAML2Request.xml");
            XmlDocument doc = new XmlDocument() { PreserveWhitespace = true };
            XmlReader reader = XmlReader.Create(new StringReader(input));

            doc.Load(reader);

            XmlSigner signer = new XmlSigner(doc);
            signer.CanonicalisationMethod = SignedXml.XmlDsigExcC14NTransformUrl;

            XmlDSigEx.Reference refr = signer.CreateReference();
            refr.Precomputed = true;
            refr.Uri = "";
            refr.DigestValue = new byte[] { 0 };
            refr.AddTransform("http://balh.com");

            var cert = new X509Certificate2(GetEmbeddedBytes("TestCustomSigning.testcert.pfx"), "password");
            RSAX509Algorithm algorithm = new RSAX509Algorithm(cert);
            algorithm.KeyInfo = X509Data.X509Certificate;

            var element = signer.GetXml(algorithm);
            string output = element.OuterXml;
           
        }

        [TestMethod]
        public void TestRsa()
        {
            string input = GetEmbeddedContent("TestCustomSigning.SAML2Request.xml");
            XmlDocument doc = new XmlDocument() { PreserveWhitespace = true };
            XmlReader reader = XmlReader.Create(new StringReader(input));

            doc.Load(reader);

            XmlSigner signer = new XmlSigner(doc);
            signer.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;
            signer.CanonicalisationMethod = SignedXml.XmlDsigExcC14NTransformUrl;

            XmlDSigEx.Reference refr = signer.CreateReference();
            refr.Uri = "";
            refr.AddTransform(SignedXml.XmlDsigEnvelopedSignatureTransformUrl);
            RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
            RsaAlgorithm algorithm = new RsaAlgorithm(csp);
            algorithm.WriteRsaKeyValue = true;

            var element = signer.GetXml(algorithm);
            string output = element.OuterXml;
            doc.DocumentElement.AppendChild(doc.ImportNode(element, true));

            SignedXml xml = new SignedXml(doc);
            xml.LoadXml(element);
            bool result = xml.CheckSignature();

            Assert.IsTrue(result);
        }

       
        [TestMethod]
        public void TestReferencedDataObject()
        {
            string input = GetEmbeddedContent("TestCustomSigning.SAML2Request.xml");
            XmlDocument doc = new XmlDocument() { PreserveWhitespace = true };
            XmlReader reader = XmlReader.Create(new StringReader(input));

            doc.Load(reader);


            XmlSigner signer = new XmlSigner();
            signer.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;
            signer.CanonicalisationMethod = SignedXml.XmlDsigExcC14NTransformUrl;

            XmlDSigEx.Reference refr = signer.CreateReference();
            refr.Uri = "#_1234";
            refr.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";

            var cert = new X509Certificate2(GetEmbeddedBytes("TestCustomSigning.testcert.pfx"), "password");
            RSAX509Algorithm algorithm = new RSAX509Algorithm(cert);
            algorithm.KeyInfo = X509Data.X509Certificate;
           
            IDataObject dataObject = signer.CreateDataObject("_1234");
            dataObject.Creating = el =>
                {
                    el.WriteRaw(doc.OuterXml);
                };

            var element = signer.GetXml(algorithm);
            string output = element.OuterXml;

            XmlDocument signature = new XmlDocument() { PreserveWhitespace = true};
            signature.AppendChild(signature.ImportNode(element, true));

            SignedXml xml = new SignedXml(signature);
            xml.LoadXml(signature.DocumentElement);
            bool result1 = xml.CheckSignature();

            XmlSigner verifier = new XmlSigner(signature);
            bool result2 = verifier.ValidateSignature(signature.DocumentElement);

            Assert.IsTrue(result1 && result2);
        }

        [TestMethod]
        public void TestManifest()
        {      
            XmlSigner signer = new XmlSigner();
            signer.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;
            XmlDSigEx.Reference refr = signer.CreateReference();
            refr.Uri = "#_1234";

            XmlDSigEx.Reference refr2 = signer.CreateReference();
            refr2.Uri = "#_4321";

            var cert = new X509Certificate2(GetEmbeddedBytes("TestCustomSigning.testcert.pfx"), "password");
            RSAX509Algorithm algorithm = new RSAX509Algorithm(cert);
            algorithm.KeyInfo = X509Data.X509Certificate;

            IDataObject dataObject = signer.CreateDataObject();
            IManifest manifest = dataObject.CreateManifest();
            manifest.ID = "_1234";
            var manifestReference = manifest.CreateReference();
            manifestReference.DigestValue = new byte[32];

            IDataObject timestamp = signer.CreateDataObject("_4321");
            timestamp.Creating = w =>
                {
                    w.WriteRaw(@"<TSTInfo xmlns=""urn:oasis:names:tc:dss:1.0:core:schema"">
            <SerialNumber>123456789</SerialNumber>
            <CreationTime>2010-04-17T00:46:02Z</CreationTime>
          </TSTInfo>");
                };


            var element = signer.GetXml(algorithm);
            string output = element.OuterXml;


            XmlDocument signature = new XmlDocument() { PreserveWhitespace = true };
            signature.AppendChild(signature.ImportNode(element, true));

            SignedXml xml = new SignedXml(signature);
            xml.LoadXml(signature.DocumentElement);
            bool result1 = xml.CheckSignature();

            XmlSigner verifier = new XmlSigner(signature);
            bool result2 = verifier.ValidateSignature(signature.DocumentElement);

            Assert.IsTrue(result1 && result2);
        }

        [TestMethod]
        public void TestBasicVerify()
        {
            string input = GetEmbeddedContent("TestCustomSigning.SAML2Request.xml");         
            var cert = new X509Certificate2(GetEmbeddedBytes("TestCustomSigning.testcert.pfx"), "password");

            XmlDocument doc = new XmlDocument() { PreserveWhitespace = true };
            doc.Load(XmlReader.Create(new StringReader(input)));

            SignedXml sXml = new SignedXml(doc);
            System.Security.Cryptography.Xml.Reference reference = new System.Security.Cryptography.Xml.Reference();
            reference.Uri = "";
            reference.DigestMethod = SignedXml.XmlDsigSHA1Url;
            reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
            sXml.AddReference(reference);

            sXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
            sXml.SigningKey = cert.PrivateKey;
            sXml.ComputeSignature();

            XmlElement signature = sXml.GetXml();
            doc.DocumentElement.AppendChild(doc.ImportNode(signature, true));

            string signed = doc.OuterXml;
            XmlDocument signedDoc = new XmlDocument() { PreserveWhitespace = true };
            signedDoc.LoadXml(signed);


            XmlSigner signer = new XmlSigner(signedDoc);
            ISignatureAlgorithm algorithm = new RSAX509Algorithm(cert);
            bool result = signer.ValidateSignature(signedDoc.DocumentElement.LastChild as XmlElement, algorithm);
            Assert.IsTrue(result);
        }

        [TestMethod]
        public void TestTransformList()
        {
            string input = GetEmbeddedContent("TestCustomSigning.SAML2Request.xml");
            var cert = new X509Certificate2(GetEmbeddedBytes("TestCustomSigning.testcert.pfx"), "password");

            XmlDocument doc = new XmlDocument() { PreserveWhitespace = true };
            doc.Load(XmlReader.Create(new StringReader(input)));

            SignedXml sXml = new SignedXml(doc);
            System.Security.Cryptography.Xml.Reference reference = new System.Security.Cryptography.Xml.Reference();
            reference.Uri = "";
            reference.DigestMethod = SignedXml.XmlDsigSHA1Url;
            reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
            sXml.AddReference(reference);

            sXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
            sXml.SigningKey = cert.PrivateKey;
            sXml.ComputeSignature();

            XmlElement signature = sXml.GetXml();
            doc.DocumentElement.AppendChild(doc.ImportNode(signature, true));

            string signed = doc.OuterXml;
            XmlDocument signedDoc = new XmlDocument() { PreserveWhitespace = true };
            signedDoc.LoadXml(signed);


            XmlSigner signer = new XmlSigner(signedDoc);
            ISignatureAlgorithm algorithm = new RSAX509Algorithm(cert);
            bool result = signer.ValidateSignature(signedDoc.DocumentElement.LastChild as XmlElement, algorithm);
            Assert.IsTrue(result);

            Assert.IsTrue(signer.References[0].Transforms.Count() == 1);
        }

        [TestMethod]
        public void TestX509KeyDataOnVerify()
        {
            string input = GetEmbeddedContent("TestCustomSigning.SAML2Request.xml");
            var cert = new X509Certificate2(GetEmbeddedBytes("TestCustomSigning.testcert.pfx"), "password");

            XmlDocument doc = new XmlDocument() { PreserveWhitespace = true };
            doc.Load(XmlReader.Create(new StringReader(input)));

            SignedXml sXml = new SignedXml(doc);
            System.Security.Cryptography.Xml.Reference reference = new System.Security.Cryptography.Xml.Reference();
            reference.Uri = "";
            reference.DigestMethod = SignedXml.XmlDsigSHA1Url;
            reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
            sXml.AddReference(reference);

            KeyInfoX509Data x509Data = new KeyInfoX509Data(cert);
            sXml.KeyInfo.AddClause(x509Data);

            sXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
            sXml.SigningKey = cert.PrivateKey;
            sXml.ComputeSignature();

            XmlElement signature = sXml.GetXml();
            doc.DocumentElement.AppendChild(doc.ImportNode(signature, true));

            string signed = doc.OuterXml;
            XmlDocument signedDoc = new XmlDocument() { PreserveWhitespace = true };
            signedDoc.LoadXml(signed);


            XmlSigner signer = new XmlSigner(signedDoc);
            ISignatureAlgorithm algorithm = new RSAX509Algorithm(cert);
            bool result = signer.ValidateSignature(signedDoc.DocumentElement.LastChild as XmlElement);
            Assert.IsTrue(result);
        }

        [TestMethod]
        public void TestSignVerifyConsistency()
        {
            string input = GetEmbeddedContent("TestCustomSigning.SAML2Request.xml");
            XmlDocument doc = new XmlDocument() { PreserveWhitespace = true };
            XmlReader reader = XmlReader.Create(new StringReader(input));
            doc.Load(reader);

            XmlSigner signer = new XmlSigner(doc);
            signer.CanonicalisationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
            signer.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512";

            XmlDSigEx.Reference refr = signer.CreateReference();
            refr.Uri = "";
            refr.DigestMethod = SignedXml.XmlDsigSHA1Url;
            refr.AddTransform(SignedXml.XmlDsigEnvelopedSignatureTransformUrl);

            var cert = new X509Certificate2(GetEmbeddedBytes("TestCustomSigning.testcert.pfx"), "password");

            RSAX509Algorithm algorithm = new RSAX509Algorithm(cert);
            algorithm.KeyInfo = X509Data.X509Certificate;

            var element = signer.GetXml(algorithm);
            string output = element.OuterXml;

            doc.DocumentElement.AppendChild(doc.ImportNode(element, true));

            string signed = doc.OuterXml;
            XmlDocument signedDoc = new XmlDocument() { PreserveWhitespace = true };
            signedDoc.Load(XmlReader.Create(new StringReader(signed)));

            XmlSigner verifier = new XmlSigner(signedDoc);
            ISignatureAlgorithm algorithm2 = new RSAX509Algorithm(cert);
            bool result = verifier.ValidateSignature(signedDoc.DocumentElement.LastChild as XmlElement, algorithm);
            Assert.IsTrue(result);
        }

        [TestMethod]
        public void TestSignVerifyConsistencyWithType()
        {
            string input = GetEmbeddedContent("TestCustomSigning.SAML2Request.xml");
            XmlDocument doc = new XmlDocument() { PreserveWhitespace = true };
            XmlReader reader = XmlReader.Create(new StringReader(input));
            doc.Load(reader);

            XmlSigner signer = new XmlSigner(doc);
            signer.CanonicalisationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
            signer.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512";

            XmlDSigEx.Reference refr = signer.CreateReference();
            refr.Uri = "";
            refr.Type = "http://www.w3.org/2000/09/xmldsig#Object";
            refr.DigestMethod = SignedXml.XmlDsigSHA1Url;
            refr.AddTransform(SignedXml.XmlDsigEnvelopedSignatureTransformUrl);

            var cert = new X509Certificate2(GetEmbeddedBytes("TestCustomSigning.testcert.pfx"), "password");

            RSAX509Algorithm algorithm = new RSAX509Algorithm(cert);
            algorithm.KeyInfo = X509Data.X509Certificate;

            var element = signer.GetXml(algorithm);
            string output = element.OuterXml;

            doc.DocumentElement.AppendChild(doc.ImportNode(element, true));

            string signed = doc.OuterXml;
            XmlDocument signedDoc = new XmlDocument() { PreserveWhitespace = true };
            signedDoc.Load(XmlReader.Create(new StringReader(signed)));

            XmlSigner verifier = new XmlSigner(signedDoc);
            ISignatureAlgorithm algorithm2 = new RSAX509Algorithm(cert);
            bool result = verifier.ValidateSignature(signedDoc.DocumentElement.LastChild as XmlElement, algorithm);
            Assert.IsTrue(result);
        }

        [TestMethod]
        public void TestECDsa()
        {
            string input = GetEmbeddedContent("TestCustomSigning.SAML2Request.xml");
            XmlDocument doc = new XmlDocument() { PreserveWhitespace = true };
            XmlReader reader = XmlReader.Create(new StringReader(input));
            doc.Load(reader);

            XmlSigner signer = new XmlSigner(doc);
            signer.CanonicalisationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
            signer.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512";

            XmlDSigEx.Reference refr = signer.CreateReference();
            refr.Uri = "";
            refr.DigestMethod = SignedXml.XmlDsigSHA1Url;
            refr.AddTransform(SignedXml.XmlDsigEnvelopedSignatureTransformUrl);

            var cert = new X509Certificate2(GetEmbeddedBytes("TestCustomSigning.testcert.pfx"), "password");

            CngKey key = CngKey.Create(CngAlgorithm.ECDsaP256);
            ECDsaAlgorithm algorithm = new ECDsaAlgorithm(key);

            var element = signer.GetXml(algorithm);
            string output = element.OuterXml;

            doc.DocumentElement.AppendChild(doc.ImportNode(element, true));

            string signed = doc.OuterXml;
            XmlDocument signedDoc = new XmlDocument() { PreserveWhitespace = true };
            signedDoc.Load(XmlReader.Create(new StringReader(signed)));

            XmlSigner verifier = new XmlSigner(signedDoc);
            ISignatureAlgorithm algorithm2 = new ECDsaAlgorithm(key);
            bool result = verifier.ValidateSignature(signedDoc.DocumentElement.LastChild as XmlElement);
            Assert.IsTrue(result);
        }

        [TestMethod]
        public void TestRsaVerify()
        {
            string input = GetEmbeddedContent("TestCustomSigning.SAML2Request.xml");
            XmlDocument doc = new XmlDocument() { PreserveWhitespace = true };
            XmlReader reader = XmlReader.Create(new StringReader(input));
            doc.Load(reader);

            XmlSigner signer = new XmlSigner(doc);
            signer.CanonicalisationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
            signer.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512";

            XmlDSigEx.Reference refr = signer.CreateReference();
            refr.Uri = "";
            refr.DigestMethod = SignedXml.XmlDsigSHA1Url;
            refr.AddTransform(SignedXml.XmlDsigEnvelopedSignatureTransformUrl);

            var cert = new X509Certificate2(GetEmbeddedBytes("TestCustomSigning.testcert.pfx"), "password");

            RSAX509Algorithm algorithm = new RSAX509Algorithm(cert);
            algorithm.WriteRsaKeyValue = true;

            var element = signer.GetXml(algorithm);
            string output = element.OuterXml;

            doc.DocumentElement.AppendChild(doc.ImportNode(element, true));

            string signed = doc.OuterXml;
            XmlDocument signedDoc = new XmlDocument() { PreserveWhitespace = true };
            signedDoc.Load(XmlReader.Create(new StringReader(signed)));

            XmlSigner verifier = new XmlSigner(signedDoc);
            bool result = verifier.ValidateSignature(signedDoc.DocumentElement.LastChild as XmlElement);
            Assert.IsTrue(result);
        }
        

        [TestMethod]
        public void TestEmptyUriFindsDocumentRoot()
        {     
            string input = "<foo xmlns=\"http://foobar\" xmlns:b=\"http://boofar\"><b:bar id=\"_123\"></b:bar></foo>";
            XmlDocument doc = new XmlDocument() { PreserveWhitespace = true };
            doc.LoadXml(input);

            XmlSigner signer = new XmlSigner(doc);
            signer.CanonicalisationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
            signer.SignatureMethod = SignedXml.XmlDsigRSASHA1Url; 

            XmlDSigEx.Reference refr = signer.CreateReference();
            refr.Uri = "";
            refr.DigestMethod = SignedXml.XmlDsigSHA1Url;
            refr.AddTransform(SignedXml.XmlDsigEnvelopedSignatureTransformUrl);

            var cert = new X509Certificate2(GetEmbeddedBytes("TestCustomSigning.testcert.pfx"), "password");

            RSAX509Algorithm algorithm = new RSAX509Algorithm(cert);
            algorithm.KeyInfo = X509Data.X509Certificate;

            var element = signer.GetXml(algorithm);
            string output = element.OuterXml;

            doc.DocumentElement.AppendChild(doc.ImportNode(element, true));

            SignedXml xml = new SignedXml(doc);
            xml.LoadXml(element);
            bool result = xml.CheckSignature();

            Assert.IsTrue(result);
        }

        [TestMethod]
        public void TestAnonymousReference()
        {
            byte[] testData = new byte[] { 1,9,2,8,3,7,4};
            XmlDocument doc = new XmlDocument() { PreserveWhitespace = true };            

            XmlSigner signer = new XmlSigner(doc);
            signer.CanonicalisationMethod = SignedXml.XmlDsigExcC14NTransformUrl;

            XmlDSigEx.Reference refr = signer.CreateReference();
            refr.Uri = null;
            refr.DigestMethod = SignedXml.XmlDsigSHA1Url;
            refr.DigestValue = testData;
            refr.Precomputed = true;

            X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
            store.Open(OpenFlags.ReadOnly);
            var cert = new X509Certificate2(GetEmbeddedBytes("TestCustomSigning.testcert.pfx"), "password");

            ISignatureAlgorithm algorithm = new RSAX509Algorithm(cert);

            var element = signer.GetXml(algorithm);
            string output = element.OuterXml;

            doc.AppendChild(doc.ImportNode(element, true));

            // TODO: How to verify?
        }

        public static string GetEmbeddedContent(string resourceName)
        {
            using (Stream resourceStream =
                 Assembly.GetAssembly(typeof(TestSigner)).GetManifestResourceStream(resourceName))
            {
                StreamReader reader = new StreamReader(resourceStream);
                return reader.ReadToEnd();
            }
        }

        public static byte[] GetEmbeddedBytes(string resourceName)
        {
            using (Stream resourceStream =
                 Assembly.GetAssembly(typeof(TestSigner)).GetManifestResourceStream(resourceName))
            using(MemoryStream stream = new MemoryStream())
            {
                resourceStream.CopyTo(stream);
                return stream.ToArray();
            }
        }
    }
}
